﻿namespace JunFan.Tests.UnitTests
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using AutoMapper;
    using Repositories;
    using Item = Domain.Item;

    public class ItemRepositoryStub : IRepository<Item>
    {
        private readonly Dictionary<int, Repositories.Dtos.Item> _items = new Dictionary<int, Repositories.Dtos.Item>();
        private int _currentId;

        public Item Create(Item item)
        {
            item.InternalId = UniqueId();

            _items[item.InternalId] = MapToDto(item);
            
            return item;
        }

        public bool Exists(Item item)
        {
            return _items.Values.Any(x => x.ExternalId == item.Id);
        }

        public Item Read(int id)
        {
            Repositories.Dtos.Item itemDto;

            _items.TryGetValue(id, out itemDto);

            return MapToDomain(itemDto);
        }

        public void Update(Item item)
        {
            var itemDto = MapToDto(item);

            _items[itemDto.Id] = itemDto;
        }

        public IEnumerable<Item> ReadAll()
        {
            return MapToDomain(_items.Values.ToList());
        }

        public  IEnumerable<Item> ReadAll(Func<Item, bool> filter)
        {
            return MapToDomain(_items.Values.Where(MapPredicate(filter)).ToList());
        }

        #region Mapping

        protected static Item MapToDomain(Repositories.Dtos.Item dto)
        {
            return Mapper.Map<Item>(dto);
        }

        protected IEnumerable<Item> MapToDomain(List<Repositories.Dtos.Item> dtos)
        {
            return Mapper.Map<List<Repositories.Dtos.Item>, List<Item>>(dtos);
        }

        protected static Repositories.Dtos.Item MapToDto(Item item)
        {
            return Mapper.Map<Repositories.Dtos.Item>(item);
        }

        protected Func<Repositories.Dtos.Item, bool> MapPredicate(Func<Item, bool> predicate)
        {
            Func<Repositories.Dtos.Item, Item> mappingFunc = Mapper.CreateMapExpression<Repositories.Dtos.Item, Item>().Compile();
            return x => predicate(mappingFunc(x));
        }

        #endregion Mapping

        # region Non repository methods
        private int UniqueId()
        {
            return ++_currentId;
        }
        # endregion Non repository methods
    }
}